<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>变量的解构赋值</title>
  </head>
  <body>
    <script>
      /**
       * 数组的解构赋值
       *   数组的解构赋值会从数组的对应位置提取值，然后赋值给变量
       *   本质上，这种写法属于“模式匹配”，只要等号两边的模式相同，左边的变量就会被赋予对应的值
       */

      //这里变量的值来自数组所以要加上[]
      // let[a,b,c] =[1,2,3]

      // let[a,[b,c,d],e] = [1,[3,5,7],10];
      // console.log(a,b,c,d,e);

      /**
       * 如果解构不成功，变量的值就等于undefined。
       */
      // let[a,b,c] =[1,2];
      // console.log(a,b,c);

      /**
       * 如果等号的右边不是数组（或者严格地说，不是可遍历的结构，参见《Iterator》一章），那么将会报错。
       */
      // 报错
      // let [foo] = 1;
      // let [foo] = false;
      // let [foo] = NaN;
      // let [foo] = undefined;
      // let [foo] = null;
      // let [foo] = {};

      // 对于 Set 结构，也可以使用数组的解构赋值。

      // let [x, y, z] = new Set(['a', 'b', 'c']);

      //默认值：在数组解构的时候变量对应的数组的位置如果没有相应的值的话那么该变量会指定为undefined
      //设置默认值的话当变量被赋值为undefined的时候会自动使用默认值

      // let [a,b=2]=[1]

      // let [a,b,c=12] = [18,20,undefined];

      /**
       * 默认值可以引用解构赋值的其他变量，但该变量必须已经声明。
       */

      //  let [a,b=a] = [];//undefined  undefined
      //  console.log(a,b);

      //   let [x = 1, y = x] = []; // x=1; y=1
      //   let [x = 1, y = x] = [2]; // x=2; y=2
      //   let [x = 1, y = x] = [1, 2]; // x=1; y=2
      //   let [x = y, y = 1] = []; // ReferenceError: y is not defined x用y做默认值时，y还没有声明

      /**
       * 对象的解构赋值
       * 对象的解构与数组有一个重要的不同。数组的元素是按次序排列的，变量的取值由它的位置决定；
       * 而对象的属性没有次序，变量必须与属性同名，才能取到正确的值。
       */

      // let{name,age} ={name:'lily',age:34}
      // console.log(name,age);

      let user = {
        name: "Jack",
        age: 23,
        score: 78,
      };

      /**
       * 如果变量和对象中的属性名不一样，要使用这种方式
       * 注意下面代码的意思是找到user对象中的name属性，赋值给username变量，最后正在拥有值的是username
       */
      // let{name:username,age:userage} =user;
      // console.log(username,userage);

      /**
       * 默认值 对象的解构赋值和数组类似，也可以设置默认值，当对应的对象中的属性如果值为undefined类型时会使用默认值
       */

      //   var { x = 3 } = {};
      //   x; // 3

      //   var { x, y = 5 } = { x: 1 };
      //   x; // 1
      //   y; // 5

      //   var { x: y = 3 } = {};
      //   y; // 3

      //   var { x: y = 3 } = { x: 5 };
      //   y; // 5

      //   var { message: msg = "Something went wrong" } = {};
      //   msg; // "Something went wrong"

      //默认值生效的条件是，对象的属性值严格等于undefined。

      //   var { x = 3 } = { x: undefined };
      //   x; // 3

      //   var { x = 3 } = { x: null };
      //   x; // null
      //上面代码中，属性x等于null，因为null与undefined不严格相等，所以是个有效的赋值，导致默认值3不会生效。

      /***
       * 字符串的解构赋值
       * */

      //   const [a, b, c, d, e] = "hello";
      //   a; // "h"
      //   b; // "e"
      //   c; // "l"
      //   d; // "l"
      //   e; // "o"
      //   //类似数组的对象都有一个length属性，因此还可以对这个属性解构赋值。

      //   let { length: len } = "hello";
      //   len; // 5

      /**
       * 数值和布尔值的解构赋值
       */

      //解构赋值时，如果等号右边是数值和布尔值，则会先转为对象。

      //   let { toString: s } = 123;
      //   s === Number.prototype.toString; // true

      //   let { toString: s } = true;
      //   s === Boolean.prototype.toString; // true
      //   //上面代码中，数值和布尔值的包装对象都有toString属性，因此变量s都能取到值。

      //   //解构赋值的规则是，只要等号右边的值不是对象或数组，就先将其转为对象。由于undefined和null无法转为对象，所以对它们进行解构赋值，都会报错。

      //   let { prop: x } = undefined; // TypeError
      //   let { prop: y } = null; // TypeError

      /**
       * 函数参数的解构赋值
       */

      /**
       * 上面代码中，函数add的参数表面上是一个数组，但在传入参数的那一刻，数组参数就被解构成变量x和y。对于函数内部的代码来说，
       * 它们能感受到的参数就是x和y。
       */
      //   function add([x, y]) {
      //     return x + y;
      //   }
      //   add([1, 2]); // 3

      /*函数参数的解构也可以使用默认值。*/

      /**
       * 函数的默认参数
       */
      // function foo1(user= {name:'Lily'}){  //当函数在调用的时候如果不传参数的话就会用到默认值
      //     console.log(user.name);
      // }

      // // foo1(user)
      // // foo1()
      // //foo1({});

      // function foo({name,age} = {name:'Alice',age:12}){
      //     console.log(name,age);
      // }

      // // foo(user);
      // // foo({name:'Tom'});// Tom undefined 这里传参了就不会用到函数的默认参数
      // foo();

      /*
      ={name:'Tom',age:12}是在考虑如果函数在调用的时候不传递参数就会使用这个默认的参数 解构赋值也会从这个对象中找到值
       {name="Luvc",age=15} 如果函数在调用的时候传递的对象没有这两个属性，但是我要用到这两个属性
    */
      // function foo({name="Luvc",age=15} ={name:'Tom',age:12}){

      // }

      //   function move({ x = 0, y = 0 } = {}) {
      //     return [x, y];
      //   }

      //   move({ x: 3, y: 8 }); // [3, 8]
      //   move({ x: 3 }); // [3, 0]
      //   move({}); // [0, 0]
      //   move(); // [0, 0]

      //   function move({ x, y } = { x: 0, y: 0 }) {
      //     return [x, y];
      //   }

      //   move({ x: 3, y: 8 }); // [3, 8]
      //   move({ x: 3 }); // [3, undefined]
      //   move({}); // [undefined, undefined]
      //   move(); // [0, 0]

      /**
       * 变量赋值的用途
       */

      //交换变量
      //   let x = 1;
      //   let y = 2;
      //   [x, y] = [y, x];

      //     2）从函数返回多个值

      // 函数只能返回一个值，如果要返回多个值，只能将它们放在数组或对象里返回。有了解构赋值，取出这些值就非常方便。

      // 返回一个数组

      //   function example() {
      //     return [1, 2, 3];
      //   }
      //   let [a, b, c] = example();

      //   // 返回一个对象

      //   function example() {
      //     return {
      //       foo: 1,
      //       bar: 2,
      //     };
      //   }
      //   let { foo, bar } = example();

      //     （4）提取 JSON 数据

      // 解构赋值对提取 JSON 对象中的数据，尤其有用。

      //   let jsonData = {
      //     id: 42,
      //     status: "OK",
      //     data: [867, 5309],
      //   };

      //   let { id, status, data: number } = jsonData;

      //   console.log(id, status, number);
      //   // 42, "OK", [867, 5309]

      //     6）遍历 Map 结构

      // 任何部署了 Iterator 接口的对象，都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口，配合变量的解构赋值，获取键名和键值就非常方便。

    //   const map = new Map();
    //   map.set("first", "hello");
    //   map.set("second", "world");

    //   for (let [key, value] of map) {
    //     console.log(key + " is " + value);
    //   }
    //   // first is hello
    //   // second is world
    //   // 如果只想获取键名，或者只想获取键值，可以写成下面这样。

    //   // 获取键名
    //   for (let [key] of map) {
    //     // ...
    //   }

    //   // 获取键值
    //   for (let [, value] of map) {
    //     // ...
    //   }
    </script>
  </body>
</html>
